/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.spi.entity.info;

import com.inspur.edp.cef.spi.entity.AssociationInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.RefDataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleAssoUdtPropertyInfo;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import lombok.var;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class CefDataTypeInfo {

    private String displayValueKey;

    private Map<String, DataTypePropertyInfo> propertyInfos = new LinkedHashMap<>();

    private volatile Map<String, DataTypePropertyInfo> propertyInfosWithCamel;
    private  Object propertyInfosWithCamelLock = new Object();

    public CefDataTypeInfo(String displayValueKey) {
        this.displayValueKey = displayValueKey;
    }

    public String getDisplayValueKey() {
        return displayValueKey;
    }

    public Map<String, DataTypePropertyInfo> getPropertyInfos() {
        return propertyInfos;
    }

    public boolean containsPropertyInfo(String key) {
        if (propertyInfosWithCamel == null)
            initPropertyInfosWithCamel();
        return propertyInfosWithCamel.containsKey(key);

    }

    public DataTypePropertyInfo getPropertyInfo(String key) {
        return getPropertyInfo(key,false);
    }

    public DataTypePropertyInfo getPropertyInfo(String key,boolean containsRef)
    {
        if (propertyInfosWithCamel == null)
            initPropertyInfosWithCamel();
        return propertyInfosWithCamel.get(key);
    }

    public final DataTypePropertyInfo getPropertyInfoWithReinit(String key,boolean containsRef) {
        if (propertyInfosWithCamel == null)
            initPropertyInfosWithCamel();
        return propertyInfosWithCamel.get(key);
    }

    public final  DataTypePropertyInfo getPropertyInfoWithoutCache(String propertyName)
    {
        if(propertyName==null||"".equalsIgnoreCase(propertyName))
            throw new RuntimeException("传入属性名称为空");
        for(Map.Entry<String,DataTypePropertyInfo> entry:propertyInfos.entrySet())
        {
            if(entry.getKey().equalsIgnoreCase(propertyName))
                return entry.getValue();
        }
        for(Map.Entry<String,DataTypePropertyInfo> infoItem:propertyInfos.entrySet())
        {
            if (infoItem.getValue().getObjectInfo() instanceof AssocationPropertyInfo) {
                AssociationInfo association = ((AssocationPropertyInfo) infoItem.getValue().getObjectInfo()).getAssociationInfo();
                for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getRefPropInfos().entrySet()) {
                   if(propertyName.equalsIgnoreCase(refItem.getValue().getPropertyName()))
                       return refItem.getValue();
                }
                for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getEnrichedRefPropInfos().entrySet()) {
                    if(propertyName.equalsIgnoreCase(refItem.getValue().getPropertyName()))
                        return refItem.getValue();
                }
            } else if (infoItem.getValue().getObjectInfo() instanceof SimpleAssoUdtPropertyInfo) {
                AssociationInfo association = ((SimpleAssoUdtPropertyInfo) infoItem.getValue().getObjectInfo()).getAssoInfo().getAssociationInfo();
                for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getRefPropInfos().entrySet()) {
                    if(propertyName.equalsIgnoreCase(refItem.getValue().getPropertyName()))
                        return refItem.getValue();
                }
                for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getEnrichedRefPropInfos().entrySet()) {
                    if(propertyName.equalsIgnoreCase(refItem.getValue().getPropertyName()))
                        return refItem.getValue();
                }
            }
        }
        return null;
    }

    private void initPropertyInfosWithCamel() {
        synchronized (propertyInfosWithCamelLock){
            if(propertyInfosWithCamel != null)
                return;

            Map map=new HashMap<>();
            for (var infoItem : propertyInfos.entrySet()) {
                String key = infoItem.getKey();
                map.put(key, infoItem.getValue());
                if (key.equals(StringUtils.toCamelCase(key)) == false)
                    map.put(StringUtils.toCamelCase(key), infoItem.getValue());

                if (infoItem.getValue().getObjectInfo() instanceof AssocationPropertyInfo) {
                    AssociationInfo association = ((AssocationPropertyInfo) infoItem.getValue().getObjectInfo()).getAssociationInfo();
                    for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getRefPropInfos().entrySet()) {
                        if (refItem.getValue() instanceof RefDataTypePropertyInfo) {
                            RefDataTypePropertyInfo refDataTypePropertyInfo = (RefDataTypePropertyInfo) refItem.getValue();
                            if (refDataTypePropertyInfo.getBelongPropertyInfo() == null)
                                refDataTypePropertyInfo.setBelongPropertyInfo(infoItem.getValue());
                        }
                        map.put(refItem.getKey(), refItem.getValue());
                    }
                    for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getEnrichedRefPropInfos().entrySet()) {
                        if (refItem.getValue() instanceof RefDataTypePropertyInfo) {
                            RefDataTypePropertyInfo refDataTypePropertyInfo = (RefDataTypePropertyInfo) refItem.getValue();
                            if (refDataTypePropertyInfo.getBelongPropertyInfo() == null)
                                refDataTypePropertyInfo.setBelongPropertyInfo(infoItem.getValue());
                        }
                        map.put(refItem.getKey(), refItem.getValue());
                    }
                } else if (infoItem.getValue().getObjectInfo() instanceof SimpleAssoUdtPropertyInfo) {
                    AssociationInfo association = ((SimpleAssoUdtPropertyInfo) infoItem.getValue().getObjectInfo()).getAssoInfo().getAssociationInfo();
                    for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getRefPropInfos().entrySet()) {
                        if (refItem.getValue() instanceof RefDataTypePropertyInfo) {
                            RefDataTypePropertyInfo refDataTypePropertyInfo = (RefDataTypePropertyInfo) refItem.getValue();
                            if (refDataTypePropertyInfo.getBelongPropertyInfo() == null)
                                refDataTypePropertyInfo.setBelongPropertyInfo(infoItem.getValue());
                        }
                        map.put(refItem.getKey(), refItem.getValue());
                    }
                    for (Map.Entry<String, DataTypePropertyInfo> refItem : association.getEnrichedRefPropInfos().entrySet()) {
                        if (refItem.getValue() instanceof RefDataTypePropertyInfo) {
                            RefDataTypePropertyInfo refDataTypePropertyInfo = (RefDataTypePropertyInfo) refItem.getValue();
                            if (refDataTypePropertyInfo.getBelongPropertyInfo() == null)
                                refDataTypePropertyInfo.setBelongPropertyInfo(infoItem.getValue());
                        }
                        map.put(refItem.getKey(), refItem.getValue());
                    }
                }
            }
            this.propertyInfosWithCamel = map;
        }
    }

    private Map<String, DataTypePropertyInfo> propertyInfosWithLower;

    public boolean containsPropertyInfoByLower(String key) {
        if (propertyInfosWithLower == null)
            initPropertyInfosWithLower();
        return propertyInfosWithLower.containsKey(key);

    }

    public DataTypePropertyInfo getPropertyInfoByLower(String key) {
        if (propertyInfosWithCamel == null)
            initPropertyInfosWithLower();
        return propertyInfosWithLower.get(key);
    }

    private void initPropertyInfosWithLower() {
        propertyInfosWithLower = new HashMap<>();
        for (var infoItem : propertyInfos.entrySet()) {
            String key = infoItem.getKey();
            propertyInfosWithLower.put(key, infoItem.getValue());
            if (key.equals(key.toLowerCase()))
                continue;
            propertyInfosWithLower.put(key.toLowerCase(), infoItem.getValue());
        }
    }
}
